package com.filldream.fastboot.common.util;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.text.DecimalFormat;
import java.util.Base64;

import cn.hutool.crypto.digest.MD5;
import com.filldream.fastboot.common.constant.FinalStr;
import com.filldream.fastboot.common.exception.GlobalException;
import com.filldream.fastboot.common.entity.ErrorCode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.web.multipart.MultipartFile;

/**
 * 文件以及IO工具类
 * @author RickSun
 *
 */
@Slf4j
public class FileIOUtil {

	/**
	 * 文件相关踩坑笔记：
	 * 1、用流下载文件的时候文件名最好不要出现特殊字符，如 $&,/\等等
	 **/

	private static final DecimalFormat DF = new DecimalFormat("0.00");

	/**
	 * 定义GB的计算常量
	 */
	private static final int GB = 1024 * 1024 * 1024;
	/**
	 * 定义MB的计算常量
	 */
	private static final int MB = 1024 * 1024;
	/**
	 * 定义KB的计算常量
	 */
	private static final int KB = 1024;

	/**
	 * URL资源转换为byte[]
	 * @param url
	 * @return
	 * @throws IOException
	 */
	public static byte[] url2byte(String url) throws IOException{
		URL httpUrl = new URL(url);
		HttpURLConnection conn = (HttpURLConnection)httpUrl.openConnection();
		//设置超时间为3秒
		conn.setConnectTimeout(3*1000);
		//防止屏蔽程序抓取而返回403错误
		conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");

		//得到输入流
		InputStream inputStream = conn.getInputStream();
		//获取自己数组
		byte[] getData = readInputStreamToBytes(inputStream);
		if(inputStream != null) { inputStream.close(); }
		return getData;
	}

	/**
	 * 将输入流转换为byte数组
	 * @param inputStream
	 * @return byte数组
	 * @throws IOException
	 */
	public static  byte[] readInputStreamToBytes(InputStream inputStream) throws IOException {
		byte[] buffer = new byte[1024];
		int len = 0;
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		while((len = inputStream.read(buffer)) != -1) {
			bos.write(buffer, 0, len);
		}
		bos.close();
		return bos.toByteArray();
	}

	/**
	 * 图片url转BASE64字符串
	 * @param url
	 * @return
	 * @throws IOException
	 */
	public static String imgUrl2Base64( String url ) throws IOException {
		byte[] bytes = url2byte(url);
		return StringUtil.encodeBase64(bytes);
	}

	/**
	 * 获取中文文件名
	 * @param fileName	文件名，若不填则为uuid
	 * @return
	 */
	public static String getFileChineseName( String fileName ){
		//设置文件名称,默认uuid，中文需转码
		if (fileName == null && StringUtils.isBlank(fileName)) {
			fileName = RandomUtil.randomUUID();
		} else{
			try {
				fileName = URLEncoder.encode(fileName, "UTF-8");
			} catch (UnsupportedEncodingException e) {
				throw new GlobalException(ErrorCode.BASE_ERR.reMsg("获取中文名称错误"),e,true);
			}
		}
		return  fileName;
	}

	/**
	 * 创建多重文件夹
	 * @param path 文件夹路径
	 * @return true-成功 false-失败
	 */
	public static Boolean newDirectory(String path) {
		File file = new File(path);
		if(!file.exists() && !file.isDirectory()) {
			return file.mkdirs();
		}
		return true;
	}

	/**
	 * 删除文件或文件夹
	 * @param path 文件全路径
	 * @return true-成功 false-失败
	 */
	public static boolean deleteFiles(String path) {
		File file = new File(path);
		if (!file.exists()) {
			return false;
		} else {
			if (file.isFile()) {
				return deleteFile(path);
			} else {
				return deleteDirectory(path);
			}
		}
	}

	/**
	 * 删除目录以及目录下所有文件
	 * @param dir 目录路径
	 * @return true-成功 false-失败
	 */
	public static boolean deleteDirectory(String dir) {
		// 如果dir不以文件分隔符结尾，自动添加文件分隔符
		if (!dir.endsWith(File.separator)) {
			dir = dir + File.separator;
		}
		File dirFile = new File(dir);
		// 如果dir对应的文件不存在，或者不是一个目录，则退出
		if ((!dirFile.exists()) || (!dirFile.isDirectory())) {
			return false;
		}
		boolean flag = true;
		// 删除文件夹中的所有文件包括子目录
		File[] files = dirFile.listFiles();
		for (int i = 0; i < files.length; i++) {
			// 删除子文件
			if (files[i].isFile()) {
				flag = FileIOUtil.deleteFile(files[i].getAbsolutePath());
				if (!flag) {
					break;
				}
			}
			// 删除子目录
			else if (files[i].isDirectory()) {
				flag = FileIOUtil.deleteDirectory(files[i]
						.getAbsolutePath());
				if (!flag) {
					break;
				}
			}
		}
		if (!flag) {
			return false;
		}
		// 删除当前目录
		if (dirFile.delete()) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 删除单个文件
	 * @param path 文件路径
	 * @return  true-成功 false-失败
	 */
	public static boolean deleteFile(String path) {
		File file = new File(path);
		// 如果文件路径所对应的文件存在，并且是一个文件，则直接删除
		if (file.exists() && file.isFile()) {
			if (file.delete()) {
				return true;
			} else {
				return false;
			}
		} else {
			return false;
		}
	}

	/**
	 * 获取文校验文件md5
	 * @param filePath	文件本地地址
	 * @return	md5
	 */
	public static String toMd5(String filePath)  {
		try( BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(filePath))){
			return new MD5().digestHex(bufferedInputStream);
		}catch (IOException e){
			log.info( "FileIOUtil-toMd5(filePath):" + e.getMessage() );
		}
		return "";
	}

	/**
	 * 获取文校验文件md5
	 * @param bytes
	 * @return
	 */
	public static String toMd5(byte[] bytes) {
		String result = new MD5().digestHex(bytes);
		return result;
	}


	//----------其他-------

	/**
	 * 本地图片转Base64
	 * @param imgPath	图片地址
	 * @return
	 */
	public static String img2Base64(String imgPath) {
		byte[] data = null;
		//获取图片字节数组
		try {
			InputStream in = new FileInputStream(imgPath);
			data = new byte[in.available()];
			in.read(data);
			in.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		String result = StringUtil.encodeBase64(data);
		return result;
	}

	/**
	 * BASE64转图片
	 * @param base64	BASE64字符串,必须为去前缀的字符串即不含"data:image/jpg;base64,"
	 * @param filePath	图片存储路径
	 * @return
	 */
	private static String  base64ToImg(String base64,String filePath){
		if( StringUtils.isBlank(base64) ){
			return null;
		}

		try {
			//Base64解码
			byte[] b = Base64.getDecoder().decode(base64);
			for (int i = 0; i < b.length; i++) {
				if (b[i] < 0) {
					b[i] += 256;
				}
			}
			File file  = new File(filePath);
			if(file.exists()){
				file.delete();
			}
			FileOutputStream fos = new FileOutputStream(file);
			fos.write(b);
			fos.flush();
			fos.close();
			return filePath;
		}catch(Exception e){
			return null;
		}
	}

	/**
	 * 下载网络资源
	 * @param urlStr           网络URL
	 * @param fullFileName         自定义文件名称,全名称
	 * @param savePath         存储位置，文件夹
	 * @throws IOException
	 */
	public static void  downLoadFromUrl(String urlStr,String fullFileName,String savePath) throws IOException{
		byte[] getData = url2byte(urlStr);

		//文件保存位置
		File saveDir = new File(savePath);
		if(!saveDir.exists()){
			saveDir.mkdir();
		}
		File file = new File(saveDir+File.separator+fullFileName);
		FileOutputStream fos = new FileOutputStream(file);
		fos.write(getData);
		if(fos!=null){
			fos.close();
		}
		log.info( "FileIOUtil:"+urlStr+" download success" );
	}

	/**
	 * @author RickSun
	 * @Description 获取文件名后缀
	 * @Param fileName	文件全名，例:ifilldream.jpg
	 * @return .jpg
	 **/
	public static String getFileSuffix(String fileName){
		Assert.isEmpty(fileName,"文件名错误");
		return fileName.substring(fileName.lastIndexOf("."));
	}


	/**
	 * @author RickSun
	 * @Description 获取项目资源文件
	 * @param sourcePath 资源地址
	 * @return InputStream
	 **/
	public static InputStream getPathFile(String sourcePath) {
		try {
			InputStream certStream= new ClassPathResource(sourcePath).getInputStream();
			return certStream;
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
	}



    /**
	 * @author RickSun
	 * @Description inputstream保存文件到本地
	 **/
	public String saveToLocal(InputStream input,String directoryUrl,String fileName ){
		try {
			//目标路径
			File file = new File(directoryUrl);
			//如果文件目录不存在，就执行创建
			if(!file.isDirectory()){
				file.mkdirs();
			}
			directoryUrl +=  fileName;

			int index;
			byte[] bytes = new byte[1024];
			FileOutputStream downloadFile = new FileOutputStream(directoryUrl);
			while ((index = input.read(bytes)) != -1) {
				downloadFile.write(bytes, 0, index);
				downloadFile.flush();
			}
			downloadFile.close();
			input.close();
			return directoryUrl;
		}catch (Exception e){
			System.out.println(e.getMessage());
		}
		return "";
	}

	/**
	 * 上传文件到本地
	 * @param upFile	文件
	 * @param fileName	文件名称
	 * @return	上传失败返回null
	 */
	public static String saveFileToLocal(MultipartFile upFile  , String  fileName) {
		String path = FinalStr.getLocalFileUrl();

		File file = new File(path);
		String pathFile = path + File.separator + getFileChineseName(fileName);
		File newFile = new File(pathFile);
		//判断文件夹是否存在，不存在则创建
		if (!file.exists()) {
			//创建文件夹
			file.mkdirs();
		}

		try {
			//文件传输到本地
			upFile.transferTo(newFile);
		} catch (IOException e) {
			log.info( "-------------->本地文件存储异常:" + e.getMessage());
			return null;
		}
		log.info( "-------------->本地文件存储:" + pathFile);
		return pathFile;
	}


	public static String getSize(long size) {
		String resultSize;
		if (size / GB >= 1) {
			//如果当前Byte的值大于等于1GB
			resultSize = DF.format(size / (float) GB) + "GB   ";
		} else if (size / MB >= 1) {
			//如果当前Byte的值大于等于1MB
			resultSize = DF.format(size / (float) MB) + "MB   ";
		} else if (size / KB >= 1) {
			//如果当前Byte的值大于等于1KB
			resultSize = DF.format(size / (float) KB) + "KB   ";
		} else {
			resultSize = size + "B   ";
		}
		return resultSize;
	}


	//
	public static String genFileName(String fileName) {
		if(StringUtils.isNotBlank(fileName)){
			return fileName;
		}
		return FinalStr.project_name + "_" + System.currentTimeMillis() + "_" + RandomUtil.randomNumberString(6);
	}

}
